package com.jahe.learn.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Arrays;

/**
 * 关于buffer 的 Scattering 和 Gathering
 * Scattering 将来自 channel的数据 读取到多个buffer里。按顺序读/写满第一个再 读/写入第二个buffer。
 * Gathering 将多个buffer的数据 ，收集到一个buffer里。
 * @author: jahe.lai
 * @create: 2019-12-25 09:55
 */
public class ScatteringAndGathering {

    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        InetSocketAddress address = new InetSocketAddress(8899);
        serverSocketChannel.socket().bind(address);

        ByteBuffer[] buffers = new ByteBuffer[3];
        buffers[0] = ByteBuffer.allocate(2);
        buffers[1] = ByteBuffer.allocate(3);
        buffers[2] = ByteBuffer.allocate(4);

        // 只监听了一次，可以使用telnet命令测试。
        SocketChannel socketChannel = serverSocketChannel.accept();
        int protoLength = 2 + 3 + 4;

        while (true) {
            // 读取数据，要求数据长度是 protoLength。否则一直监听数据读取。
            int bytesRead = 0;
            while (bytesRead < protoLength) {
                long r = socketChannel.read(buffers);
                bytesRead += r;
                System.out.println("bytesRead="+bytesRead);
                // 流式打印
                Arrays.asList(buffers).stream().map(buffer -> "position: " + buffer.position() + ", limit: " + buffer.limit())
                        .forEach(System.out::println);
            }
            // 接收完长度指定的数据后，响应数据
            Arrays.asList(buffers).forEach(buffer -> {
                buffer.flip();
            });
            long bytesWriten = 0;
            while (bytesWriten < protoLength) {
                long r = socketChannel.write(buffers);
                bytesWriten += r;
            }
            Arrays.asList(buffers).forEach(buffer -> {
                buffer.clear();
            });
            System.out.println("bytesRead="+bytesRead+", bytesWriten=" + bytesWriten + ", protoLength=" + protoLength);
        }
    }
}
